#include <string>
#include <vector>
#include <memory>
#include <iostream>
#include <list>

using namespace std;

/**
 * 显式实例化
 * extern 模板表示不会在本文件中实例化，而是在其他文件中有非 extern 声明和定义
 * 避免多个文件实例化相同模板引起的开销
 */

/**
 * template.h
 */

template <typename T> class Blob {
    public:
        typedef typename vector<T>::size_type size_type;
        Blob() {}
	    Blob(initializer_list<T> il): data(make_shared<vector<T>>(il)) {}
        const T& operator[](size_type i) const
            { return (*data)[i]; }
    private:
        shared_ptr<vector<T>> data;
};

template <typename T> int compare(const T& v1, const T& v2) {
    if (less<T>()(v1, v2)) return -1;
    if (less<T>()(v2, v1)) return 1;
    return 0;
}

/**
 * template.cpp
 */

// 模板实例化定义
// 实例化文件必须为每个在其他文件中声明为 extern 的类型和函数提供一个（非 extern）的定义
template <> class Blob<string> {
    public:
        Blob() = default;
        Blob(const string &s): name(s) {}
        const char& operator[](size_t i) const
            { return name[i]; }
    private:
        string name;
};

template <> int compare(const int& v1, const int& v2) {
    if (v1 < v2) return -1;
    if (v2 < v1) return 1;
    return 0;
}

/**
 * main.cpp
 */

// 模板实例化声明
// 这些模板类型必须在程序其他位置进行实例化
// extern template class Blob<string>;
// extern template int compare(const int&, const int&);

int main()
{
    Blob<string> sa1("aaa"), sa2("bbb"); // 在其他文件中实例化（template.cpp）
    // Blob<int> 及其接受 initializer_list 的构造函数在本文件中实例化（main.cpp）
    Blob<int> a1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    Blob<int> a2(a1); // 拷贝构造函数在本文件中实例化（main.cpp）
    int i = compare(a1[0], a2[1]); // 在其他文件中实例化（template.cpp）
    cout << i << endl;
    int j = compare("ccc", "bbb"); // 在本文件中实例化（main.cpp）
    cout << j << endl;
    int k = compare(sa1[0], sa2[0]); // 在其他文件中实例化（template.cpp）
    cout << k << endl;
}